#include "device.h"
#include "peripheral.h"
#include "component.h"

/* 调试打印接口 */
#define RTC_COMP_LOG(format, ...) __OSAL_LOG("[rtc_comp.c]" C_GREEN format C_NONE "\r\n", ##__VA_ARGS__)

/* 定义虚拟硬件 */
#define RTC_VIRTUALHARDWARE vRTC_0
/* 创建环形缓存，保存处理好的命令包，准备发送给应用层 */
static RingBufferHandle_t rbRtcAlarmHandle = NULL;

static RtcCompNv_stu_t RtcCompInfo;
static uint8_t CurrAlarm = RTC_ALARM_NUM;

/**
 * @brief  设置闹钟
 * @param  timestamp：闹钟时间
 */
static ErrorStatus Rtc_SetAlarm(uint32_t timestamp)
{
	uint8_t temp[6];
	OSAL_UTC2Time(timestamp, temp);
	Device_Write(vRTC_0, temp, 6, 1);
	return SUCCESS;
}
/**
 * @brief  获取当前时间
 * @note
 */
static ErrorStatus Rtc_GetTime(uint32_t *timestamp)
{
	uint8_t temp[6];
	if (Device_Read(vRTC_0, temp, 6, 0) < 0)
	{
		return ERROR;
	}
	*timestamp = OSAL_Time2UTC(temp, 0);
	return SUCCESS;
}

/**
 * @brief  找出最近时间的闹钟
 * @note
 */
static ErrorStatus Find_Nearest_Alarm(uint8_t *index)
{
	ErrorStatus sta = ERROR;
	uint8_t i;
	uint32_t NearestAlarm_time = 0xffffffff;
	for (i = 0; i < RTC_ALARM_NUM; i++)
	{
		if (RtcCompInfo.Alarm[i].cycle > 0)
		{
			if (RtcCompInfo.Alarm[i].timestamp < NearestAlarm_time)
			{
				NearestAlarm_time = RtcCompInfo.Alarm[i].timestamp;
				*index = i;
				sta = SUCCESS;
			}
		}
	}
	return sta;
}

/**
 * @brief  存入一个闹钟事件
 * @note
 */
static ErrorStatus Save_Alarm(RtcAlarmInfor_stu_t *Alarm)
{
	uint8_t i;
	uint32_t timestamp;
	Rtc_GetTime(&timestamp);
	for (i = 0; i < RTC_ALARM_NUM; i++)
	{
		if (strcmp(RtcCompInfo.Alarm[i].name, Alarm->name) == 0)
		{
			RtcCompInfo.Alarm[i].timestamp = timestamp + Alarm->cycle;
			RtcCompInfo.Alarm[i].cycle = Alarm->cycle;
			RtcCompInfo.Alarm[i].repeat = Alarm->repeat;
			return SUCCESS;
		}
	}
	for (i = 0; i < RTC_ALARM_NUM; i++)
	{
		if (strlen(RtcCompInfo.Alarm[i].name) == 0 && RtcCompInfo.Alarm[i].cycle == 0)
		{
			memcpy(RtcCompInfo.Alarm[i].name, Alarm->name, strlen(Alarm->name));
			RtcCompInfo.Alarm[i].timestamp = timestamp + Alarm->cycle;
			RtcCompInfo.Alarm[i].cycle = Alarm->cycle;
			RtcCompInfo.Alarm[i].repeat = Alarm->repeat;
			return SUCCESS;
		}
	}
	return ERROR;
}

/**
 * @brief 更新闹钟事件
 * @note
 */
static ErrorStatus Func_Upd_RtcAlarm(void)
{
	uint8_t nearest;
	uint32_t now_timestamp;
	Rtc_GetTime(&now_timestamp);
	for (;;)
	{
		if (SUCCESS == Find_Nearest_Alarm(&nearest))
		{
			if (RtcCompInfo.Alarm[nearest].timestamp <= now_timestamp)
			{
				if (RtcCompInfo.Alarm[nearest].repeat == SET) // 重复闹钟则更新时间，非重复闹钟则删除
				{
					RtcCompInfo.Alarm[nearest].timestamp = now_timestamp + RtcCompInfo.Alarm[nearest].cycle;
				}
				else
				{
					memset((uint8_t *)&RtcCompInfo.Alarm[nearest], 0, sizeof(RtcAlarmInfor_stu_t));
				}
				continue;
			}
			for (uint8_t i = 0; i < RTC_ALARM_NUM; i++) // 先清除所有闹钟正在运行标志位,因为一次只有一个闹钟事件进行
			{
				if (strlen(RtcCompInfo.Alarm[i].name) != 0 && RtcCompInfo.Alarm[i].cycle > 0)
				{
					RtcCompInfo.Alarm[i].run = RESET;
				}
			}
			RtcCompInfo.Alarm[nearest].run = SET;

			RtcCompNv_stu_t tmp = {0};
			OSAL_NvRead(0, &tmp, sizeof(RtcCompNv_stu_t));
			if (0 != memcmp(&tmp, &RtcCompInfo, sizeof(RtcCompNv_stu_t))) // 对比，有更新才存NV
			{
				OSAL_NvWrite(0, &RtcCompInfo, sizeof(RtcCompNv_stu_t));
			}
			Rtc_SetAlarm(RtcCompInfo.Alarm[nearest].timestamp);
			CurrAlarm = nearest;
			return SUCCESS;
		}
		else
		{
			return ERROR;
		}
	}
}

/**
 * @brief  处理闹钟设置事件
 * @note
 * @param  cycle：周期
 * @param  repeat：重复标志（SET:重复创建该闹钟；RESET:单次创建该闹钟）;
 */
static ErrorStatus RtcAlarm_SetApi(RtcAlarmInfor_stu_t *Alarm)
{
	RTC_COMP_LOG("RtcAlarm_SetApi:%s,cycle:%d,repeat:%d", Alarm->name, Alarm->cycle, Alarm->repeat);
	// 没有闹钟名或者周期为0 都退出
	if (strlen(Alarm->name) == 0 || Alarm->cycle == 0)
	{
		return ERROR;
	}
	if (SUCCESS == Save_Alarm(Alarm))
	{
		return Func_Upd_RtcAlarm();
	}

	return ERROR;
}

/**
 * @brief NV初始化
 *
 */
static void RtcComp_NvInit(void)
{
	RtcCompNv_stu_t tmp;
	OSAL_NvRead(0, &tmp, sizeof(RtcCompNv_stu_t));
	if (tmp.nvInitFlag != RTC_COMP_NV_INIT_FLAG)
	{
		RTC_COMP_LOG(" RtcComp Nv Reset\r\n");
		memset(&tmp, 0, sizeof(RtcCompNv_stu_t));
		tmp.nvInitFlag = RTC_COMP_NV_INIT_FLAG;
		OSAL_NvWrite(0, &tmp, sizeof(tmp));
	}
	OSAL_NvRead(0, &RtcCompInfo, sizeof(RtcCompInfo));
	RTC_COMP_LOG("RtcComp_NvInit\r\n");
}

/**
 * @brief  RTC唤醒逻辑处理
 * @param
 * @return
 */
static void RtcAlarm_WakeHandle(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
	uint32_t nowtime;
	uint8_t time[6];
	struct tm dateTime = {0};
	memcpy((uint8_t *)&dateTime, (uint8_t *)data, sizeof(dateTime));
	time[0] = dateTime.tm_year - 100;
	time[1] = dateTime.tm_mon + 1;
	time[2] = dateTime.tm_mday;
	time[3] = dateTime.tm_hour;
	time[4] = dateTime.tm_min;
	time[5] = dateTime.tm_sec;
	nowtime = OSAL_Time2UTC(time, 0);

	if (dev == vRTC_0)
	{
		if (RtcCompInfo.Alarm[CurrAlarm].timestamp == nowtime && CurrAlarm < RTC_ALARM_NUM)
		{
			OSAL_RingBufferWrite(rbRtcAlarmHandle, &CurrAlarm);
		}
		/* 创建ISR事件 */
		OSAL_EventCreateFromISR(COMP_RTC);
	}
}

/**
 * @brief  RtcComp任务函数
 *
 * @note   1.任务函数内不能写阻塞代码
 *         2.任务函数每次运行只处理一个事件
 *
 * @param  event：当前任务的所有事件
 *
 * @return 返回未处理的事件
 */
static uint32_t RtcComp_Task(uint32_t event)
{
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
		static uint8_t initflag = 0;
		RTC_COMP_LOG("RtcComp task start\r\n");
		if (initflag == 0)
		{
			initflag = 1;
			RtcComp_NvInit();
			Func_Upd_RtcAlarm();
		}
		if (rbRtcAlarmHandle == NULL)
		{
			rbRtcAlarmHandle = OSAL_RingBufferCreate(RTC_ALARM_NUM, 1);
			/* 注册中断回调 */
			Device_RegisteredCB(vRTC_0, RtcAlarm_WakeHandle);
			RTC_COMP_LOG("RtcComp RingBuffe Init\r\n");
		}
		return (event ^ EVENT_SYS_START);
	}
	if (event & EVENT_SYS_MBOX)
	{
		RtcAlarmInfor_stu_t temp = {0};
		while (OSAL_MboxAccept(&temp))
		{
			RtcAlarm_SetApi(&temp);
		}
		return (event ^ EVENT_SYS_MBOX);
	}
	if (event & EVENT_SYS_ISR)
	{
		RTC_COMP_LOG("RtcComp ISR EVENT\r\n");
		uint8_t curr_alarm;
		while (OSAL_RingBufferRead(rbRtcAlarmHandle, (uint8_t *)&curr_alarm) == SUCCESS)
		{
			if (curr_alarm < RTC_ALARM_NUM)
				OSAL_MessagePublish(&RtcCompInfo.Alarm[curr_alarm], sizeof(RtcAlarmInfor_stu_t));
		}
		Func_Upd_RtcAlarm();
		return (event ^ EVENT_SYS_ISR);
	}
	/* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
		RTC_COMP_LOG("RtcComp task sleep\r\n");
		return (event ^ EVENT_SYS_SLEEP);
	}
	return 0;
}
COMPONENT_TASK_EXPORT(COMP_RTC, RtcComp_Task, sizeof(RtcCompNv_stu_t));
